<!DOCTYPE html>
<html lang="zh-Hans">
<head>
  <meta charset="UTF-8">
<meta name="viewport" content="width=device-width">
<meta name="theme-color" content="#222"><meta name="generator" content="Hexo 6.2.0">


  <link rel="apple-touch-icon" sizes="180x180" href="/vhuichen.ico">
  <link rel="icon" type="image/png" sizes="32x32" href="/vhuichen.ico">
  <link rel="icon" type="image/png" sizes="16x16" href="/vhuichen.ico">
  <link rel="mask-icon" href="/vhuichen.ico" color="#222">

<link rel="stylesheet" href="/css/main.css">



<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.0/css/all.min.css" integrity="sha256-AbA177XfpSnFEvgpYu1jMygiLabzPCJCRIBtR5jGc0k=" crossorigin="anonymous">
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.1.1/animate.min.css" integrity="sha256-PR7ttpcvz8qrF57fur/yAx1qXMFJeJFiA6pSzWi0OIE=" crossorigin="anonymous">

<script class="next-config" data-name="main" type="application/json">{"hostname":"vhuichen.github.io","root":"/","images":"/images","scheme":"Pisces","darkmode":false,"version":"8.13.0","exturl":false,"sidebar":{"position":"left","display":"display","padding":18,"offset":12},"copycode":{"enable":false,"style":null},"bookmark":{"enable":false,"color":"#222","save":"auto"},"mediumzoom":false,"lazyload":false,"pangu":false,"comments":{"style":"tabs","active":null,"storage":true,"lazyload":false,"nav":null},"stickytabs":false,"motion":{"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"fadeInDown","post_body":"fadeInDown","coll_header":"fadeInLeft","sidebar":"fadeInUp"}},"prism":false,"i18n":{"placeholder":"Searching...","empty":"We didn't find any results for the search: ${query}","hits_time":"${hits} results found in ${time} ms","hits":"${hits} results found"}}</script><script src="/js/config.js"></script>

    <meta name="description" content="简介Websocket 基于 TCP 的全双工通信协议，属于应用层协议，他必须依赖 HTTP 协议进行一次握手，握手成功后直接通过单个 TCP 传输数据。 特点 握手阶段使用HTTP连接； 可以发送文本，也可以发送二进制数据； 全双工通信； 协议标识符ws，加密是wss；  解决了什么问题在没有 Websocket 之前，一般是通过 HTTP 轮询或者长轮询来实现数据推送    轮询：每隔一定时间">
<meta property="og:type" content="article">
<meta property="og:title" content="WebSocket">
<meta property="og:url" content="https://vhuichen.github.io/2022/01/NetworkProtocol/WebSocket/WebSocket/index.html">
<meta property="og:site_name" content="vhuichen">
<meta property="og:description" content="简介Websocket 基于 TCP 的全双工通信协议，属于应用层协议，他必须依赖 HTTP 协议进行一次握手，握手成功后直接通过单个 TCP 传输数据。 特点 握手阶段使用HTTP连接； 可以发送文本，也可以发送二进制数据； 全双工通信； 协议标识符ws，加密是wss；  解决了什么问题在没有 Websocket 之前，一般是通过 HTTP 轮询或者长轮询来实现数据推送    轮询：每隔一定时间">
<meta property="og:locale">
<meta property="og:image" content="https://vhuichen.github.io/2022/01/NetworkProtocol/WebSocket/WebSocket/ProtocolFrame.png">
<meta property="article:published_time" content="2022-01-22T16:00:00.000Z">
<meta property="article:modified_time" content="2022-01-28T16:00:00.000Z">
<meta property="article:author" content="vhuichen">
<meta property="article:tag" content="WebSocket">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://vhuichen.github.io/2022/01/NetworkProtocol/WebSocket/WebSocket/ProtocolFrame.png">


<link rel="canonical" href="https://vhuichen.github.io/2022/01/NetworkProtocol/WebSocket/WebSocket/">



<script class="next-config" data-name="page" type="application/json">{"sidebar":"","isHome":false,"isPost":true,"lang":"zh-Hans","comments":true,"permalink":"https://vhuichen.github.io/2022/01/NetworkProtocol/WebSocket/WebSocket/","path":"2022/01/NetworkProtocol/WebSocket/WebSocket/","title":"WebSocket"}</script>

<script class="next-config" data-name="calendar" type="application/json">""</script>
<title>WebSocket | vhuichen</title>
  






  <noscript>
    <link rel="stylesheet" href="/css/noscript.css">
  </noscript>
</head>

<body itemscope itemtype="http://schema.org/WebPage" class="use-motion">
  <div class="headband"></div>

  <main class="main">
    <header class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-brand-container">
  <div class="site-nav-toggle">
    <div class="toggle" aria-label="Toggle navigation bar" role="button">
        <span class="toggle-line"></span>
        <span class="toggle-line"></span>
        <span class="toggle-line"></span>
    </div>
  </div>

  <div class="site-meta">

    <a href="/" class="brand" rel="start">
      <i class="logo-line"></i>
      <p class="site-title">vhuichen</p>
      <i class="logo-line"></i>
    </a>
      <p class="site-subtitle" itemprop="description">记录、分享</p>
  </div>

  <div class="site-nav-right">
    <div class="toggle popup-trigger">
    </div>
  </div>
</div>



<nav class="site-nav">
  <ul class="main-menu menu"><li class="menu-item menu-item-home"><a href="/" rel="section">Home</a></li><li class="menu-item menu-item-archives"><a href="/archives/" rel="section">Archives</a></li><li class="menu-item menu-item-about"><a href="/about/" rel="section">About</a></li>
  </ul>
</nav>




</div>
        
  
  <div class="toggle sidebar-toggle" role="button">
    <span class="toggle-line"></span>
    <span class="toggle-line"></span>
    <span class="toggle-line"></span>
  </div>

  <aside class="sidebar">

    <div class="sidebar-inner sidebar-nav-active sidebar-toc-active">
      <ul class="sidebar-nav">
        <li class="sidebar-nav-toc">
          Table of Contents
        </li>
        <li class="sidebar-nav-overview">
          Overview
        </li>
      </ul>

      <div class="sidebar-panel-container">
        <!--noindex-->
        <div class="post-toc-wrap sidebar-panel">
            <div class="post-toc animated"><ol class="nav"><li class="nav-item nav-level-2"><a class="nav-link" href="#%E7%AE%80%E4%BB%8B"><span class="nav-number">1.</span> <span class="nav-text">简介</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E7%89%B9%E7%82%B9"><span class="nav-number">1.1.</span> <span class="nav-text">特点</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E8%A7%A3%E5%86%B3%E4%BA%86%E4%BB%80%E4%B9%88%E9%97%AE%E9%A2%98"><span class="nav-number">1.2.</span> <span class="nav-text">解决了什么问题</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E4%B8%BB%E8%A6%81%E4%BD%BF%E7%94%A8%E5%9C%BA%E6%99%AF"><span class="nav-number">1.3.</span> <span class="nav-text">主要使用场景</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E6%8F%A1%E6%89%8B%E6%B5%81%E7%A8%8B"><span class="nav-number">2.</span> <span class="nav-text">握手流程</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E8%AF%B7%E6%B1%82%E5%A4%B4"><span class="nav-number">2.1.</span> <span class="nav-text">请求头</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%93%8D%E5%BA%94%E5%A4%B4"><span class="nav-number">2.2.</span> <span class="nav-text">响应头</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#WebSocket-%E5%8D%8F%E8%AE%AE%E5%A4%B4"><span class="nav-number">2.3.</span> <span class="nav-text">WebSocket 协议头</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#FIN"><span class="nav-number">2.3.1.</span> <span class="nav-text">FIN</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#RSV1%E3%80%81RSV2%E3%80%81RSV3"><span class="nav-number">2.3.2.</span> <span class="nav-text">RSV1、RSV2、RSV3</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#Opcode"><span class="nav-number">2.3.3.</span> <span class="nav-text">Opcode</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#Mask"><span class="nav-number">2.3.4.</span> <span class="nav-text">Mask</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#Payload-len"><span class="nav-number">2.3.5.</span> <span class="nav-text">Payload len</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#Masking-key"><span class="nav-number">2.3.6.</span> <span class="nav-text">Masking-key</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#Payload-data"><span class="nav-number">2.3.7.</span> <span class="nav-text">Payload data</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%AE%A2%E6%88%B7%E7%AB%AF%E5%BC%82%E5%B8%B8%E6%A0%A1%E9%AA%8C%E6%B5%81%E7%A8%8B"><span class="nav-number">2.4.</span> <span class="nav-text">客户端异常校验流程</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%88%86%E7%89%87%E9%80%BB%E8%BE%91"><span class="nav-number">2.5.</span> <span class="nav-text">分片逻辑</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E6%8E%A7%E5%88%B6%E5%91%BD%E4%BB%A4"><span class="nav-number">2.6.</span> <span class="nav-text">控制命令</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%BF%83%E8%B7%B3%E6%9C%BA%E5%88%B6"><span class="nav-number">2.7.</span> <span class="nav-text">心跳机制</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%AE%89%E5%85%A8"><span class="nav-number">2.8.</span> <span class="nav-text">安全</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E7%96%91%E9%97%AE"><span class="nav-number">2.9.</span> <span class="nav-text">疑问</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#1-TCP-UDP-%E5%8D%8F%E8%AE%AE%E5%A4%B4%E9%83%A8%E9%83%BD%E6%9C%89%E7%AB%AF%E5%8F%A3%E3%80%81%E5%92%8C%E6%A0%A1%E9%AA%8C%E8%BF%99%E4%BA%9B%EF%BC%8C%E4%B8%BA%E4%BB%80%E4%B9%88-websocket-%E6%B2%A1%E6%9C%89"><span class="nav-number">2.9.1.</span> <span class="nav-text">1. TCP UDP 协议头部都有端口、和校验这些，为什么 websocket 没有</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#2-%E4%B8%BA%E4%BB%80%E4%B9%88%E5%AE%A2%E6%88%B7%E7%AB%AF%E5%8F%91%E9%80%81%E6%95%B0%E6%8D%AE%E9%9C%80%E8%A6%81%E6%8E%A9%E7%A0%81%EF%BC%8C%E6%9C%8D%E5%8A%A1%E7%AB%AF%E5%8F%91%E9%80%81%E6%95%B0%E6%8D%AE%E5%8F%88%E4%B8%8D%E9%9C%80%E8%A6%81%E6%8E%A9%E7%A0%81"><span class="nav-number">2.9.2.</span> <span class="nav-text">2. 为什么客户端发送数据需要掩码，服务端发送数据又不需要掩码</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#3-websocket-%E6%80%8E%E4%B9%88%E5%A4%84%E7%90%86%E7%B2%98%E5%8C%85%E6%8B%86%E5%8C%85%E9%97%AE%E9%A2%98%E7%9A%84"><span class="nav-number">2.9.3.</span> <span class="nav-text">3. websocket 怎么处理粘包拆包问题的</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%8F%82%E8%80%83"><span class="nav-number">2.10.</span> <span class="nav-text">参考</span></a></li></ol></li></ol></div>
        </div>
        <!--/noindex-->

        <div class="site-overview-wrap sidebar-panel">
          <div class="site-author site-overview-item animated" itemprop="author" itemscope itemtype="http://schema.org/Person">
    <img class="site-author-image" itemprop="image" alt="vhuichen"
      src="/images/vhuichen.jpg">
  <p class="site-author-name" itemprop="name">vhuichen</p>
  <div class="site-description" itemprop="description"></div>
</div>
<div class="site-state-wrap site-overview-item animated">
  <nav class="site-state">
      <div class="site-state-item site-state-posts">
        <a href="/archives/">
          <span class="site-state-item-count">78</span>
          <span class="site-state-item-name">posts</span>
        </a>
      </div>
      <div class="site-state-item site-state-categories">
          <a href="/categories/">
        <span class="site-state-item-count">11</span>
        <span class="site-state-item-name">categories</span></a>
      </div>
      <div class="site-state-item site-state-tags">
          <a href="/tags/">
        <span class="site-state-item-count">86</span>
        <span class="site-state-item-name">tags</span></a>
      </div>
  </nav>
</div>



        </div>
      </div>
    </div>
  </aside>
  <div class="sidebar-dimmer"></div>


    </header>

    
  <div class="back-to-top" role="button" aria-label="Back to top">
    <i class="fa fa-arrow-up"></i>
    <span>0%</span>
  </div>

<noscript>
  <div class="noscript-warning">Theme NexT works best with JavaScript enabled</div>
</noscript>


    <div class="main-inner post posts-expand">


  


<div class="post-block">
  
  

  <article itemscope itemtype="http://schema.org/Article" class="post-content" lang="zh-Hans">
    <link itemprop="mainEntityOfPage" href="https://vhuichen.github.io/2022/01/NetworkProtocol/WebSocket/WebSocket/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/vhuichen.jpg">
      <meta itemprop="name" content="vhuichen">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="vhuichen">
      <meta itemprop="description" content="">
    </span>

    <span hidden itemprop="post" itemscope itemtype="http://schema.org/CreativeWork">
      <meta itemprop="name" content="WebSocket | vhuichen">
      <meta itemprop="description" content="">
    </span>
      <header class="post-header">
        <h1 class="post-title" itemprop="name headline">
          WebSocket
        </h1>

        <div class="post-meta-container">
          <div class="post-meta">
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-calendar"></i>
      </span>
      <span class="post-meta-item-text">Posted on</span>

      <time title="Created: 2022-01-23 00:00:00" itemprop="dateCreated datePublished" datetime="2022-01-23T00:00:00+08:00">2022-01-23</time>
    </span>
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-calendar-check"></i>
      </span>
      <span class="post-meta-item-text">Edited on</span>
      <time title="Modified: 2022-01-29 00:00:00" itemprop="dateModified" datetime="2022-01-29T00:00:00+08:00">2022-01-29</time>
    </span>
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-folder"></i>
      </span>
      <span class="post-meta-item-text">In</span>
        <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
          <a href="/categories/%E7%BD%91%E7%BB%9C%E5%8D%8F%E8%AE%AE/" itemprop="url" rel="index"><span itemprop="name">网络协议</span></a>
        </span>
    </span>

  
</div>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">
        <h2 id="简介"><a href="#简介" class="headerlink" title="简介"></a>简介</h2><p>Websocket 基于 TCP 的全双工通信协议，属于应用层协议，他必须依赖 HTTP 协议进行一次握手，握手成功后直接通过单个 TCP 传输数据。</p>
<h3 id="特点"><a href="#特点" class="headerlink" title="特点"></a>特点</h3><ol>
<li>握手阶段使用HTTP连接；</li>
<li>可以发送文本，也可以发送二进制数据；</li>
<li>全双工通信；</li>
<li>协议标识符ws，加密是wss；</li>
</ol>
<h3 id="解决了什么问题"><a href="#解决了什么问题" class="headerlink" title="解决了什么问题"></a>解决了什么问题</h3><p>在没有 Websocket 之前，一般是通过 HTTP 轮询或者长轮询来实现数据推送  </p>
<ul>
<li>轮询：每隔一定时间发出一个请求，耗资源</li>
<li>长轮询：客户端发送一个超长时间的请求，服务器 hold 住这个请求，直到有新数据时返回</li>
</ul>
<p>这两种方式都比较耗资源，而 Websocket 可以很好的解决这类问题</p>
<h3 id="主要使用场景"><a href="#主要使用场景" class="headerlink" title="主要使用场景"></a>主要使用场景</h3><ol>
<li>股票行情推送</li>
<li>消息推送</li>
<li>IM聊天</li>
</ol>
<h2 id="握手流程"><a href="#握手流程" class="headerlink" title="握手流程"></a>握手流程</h2><p>通过 HTTP 连接，连接完成后用 TCP 通信</p>
<h3 id="请求头"><a href="#请求头" class="headerlink" title="请求头"></a>请求头</h3><p>客户端发起带有 Upgrade 字段的 Get 请求，请求头字段如下：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">Connection: Upgrade</span><br><span class="line">Upgrade: websocket</span><br><span class="line">Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits</span><br><span class="line">Sec-WebSocket-Key: AAAAAAAA==</span><br><span class="line">Sec-WebSocket-Version: 13</span><br></pre></td></tr></table></figure>

<ol>
<li><strong>Connection</strong> ：表示要升级协议</li>
<li><strong>Upgrade</strong> ：要升级的协议是 websocket</li>
<li><strong>Sec-WebSocket-Extensions</strong> ：表示客户端所希望执行的扩展（如消息压缩插件）</li>
<li><strong>Sec-WebSocket-Key</strong> ：webSocket 协议校验值，服务端拼接一段固定字符串后加密返回回来，防止错误连接</li>
<li><strong>Sec-WebSocket-Version</strong> ：websocket 的版本<span id="more"></span></li>
</ol>
<h3 id="响应头"><a href="#响应头" class="headerlink" title="响应头"></a>响应头</h3><p>HTTP返回101状态码，表示同意升级协议</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">Connection: Upgrade</span><br><span class="line">Upgrade: websocket</span><br><span class="line">Sec-Websocket-Accept: XXXXXXXX==</span><br></pre></td></tr></table></figure>

<ol>
<li>Connection ：表示要升级协议</li>
<li>Upgrade： 表示要升级到对应的协议</li>
<li>Sec-Websocket-Accept： Sec-WebSocket-Key 的值加密后得到的值，用来给客户端校验</li>
</ol>
<h3 id="WebSocket-协议头"><a href="#WebSocket-协议头" class="headerlink" title="WebSocket 协议头"></a>WebSocket 协议头</h3><img src="/2022/01/NetworkProtocol/WebSocket/WebSocket/ProtocolFrame.png" class title="ProtocolFrame">

<p>协议头最少2个字节，最多14个字节（基本头2字节 + Extended payload 8字节 +  Masking-key 4字节）</p>
<h4 id="FIN"><a href="#FIN" class="headerlink" title="FIN"></a>FIN</h4><p>0 ：表示不是消息的最后一个分片（fragment）<br>1 ：表示消息的最后一个分片</p>
<h4 id="RSV1、RSV2、RSV3"><a href="#RSV1、RSV2、RSV3" class="headerlink" title="RSV1、RSV2、RSV3"></a>RSV1、RSV2、RSV3</h4><p>应该是 reserve 的简称，表示保留字段；用来给扩展用的</p>
<h4 id="Opcode"><a href="#Opcode" class="headerlink" title="Opcode"></a>Opcode</h4><p>操作码</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">0：表示延续帧；0 ：表示本次数据传输采用了数据分片，除了首位分片，其他的中间分片需要使用这个标志位</span><br><span class="line">1：表示文本帧</span><br><span class="line">2：表示二进制帧</span><br><span class="line">3-7：保留</span><br><span class="line">8：表示连接断开</span><br><span class="line">9：表示 ping 操作</span><br><span class="line">A：表示 pong 操作</span><br><span class="line">B-F：保留</span><br></pre></td></tr></table></figure>

<h4 id="Mask"><a href="#Mask" class="headerlink" title="Mask"></a>Mask</h4><p>0 ：服务端向客户端发送数据<br>1 ：客户端向服务端发送数据，此时会定义一个掩码键（Masking key），用来对数据反掩码</p>
<h4 id="Payload-len"><a href="#Payload-len" class="headerlink" title="Payload len"></a>Payload len</h4><p>假设 Payload len &#x3D;&#x3D; x，那么当</p>
<p>x &#x3D;&#x3D; 0 ~ 126 ：表示数据的长度为 x 字节；<br>x &#x3D;&#x3D; 126 ：表示后续2个字节的值为数据的长度（大端模式）；<br>x &#x3D;&#x3D; 127 ：表示后续8个字节的值为数据的长度；</p>
<h4 id="Masking-key"><a href="#Masking-key" class="headerlink" title="Masking-key"></a>Masking-key</h4><p>用来对数据反掩码</p>
<h4 id="Payload-data"><a href="#Payload-data" class="headerlink" title="Payload data"></a>Payload data</h4><p>扩展数据：如果需要使用必须在握手阶段协商好数据长度；<br>应用数据：剩下的就是应用数据长度了；</p>
<h3 id="客户端异常校验流程"><a href="#客户端异常校验流程" class="headerlink" title="客户端异常校验流程"></a>客户端异常校验流程</h3><ol>
<li>检查服务端返回的状态码是否为 101, 代表服务端同意了协议升级</li>
<li>检查服务端响应是否包含 Upgrade 字段, 若缺失, 则终止握手</li>
<li>检查 Upgrade 字段的值是否为 websocket ，若不是, 则终止握手</li>
<li>校验服务端返回的 Sec-WebSocket-Accept 字段的值是否合法, 若不合法则，终止握手</li>
<li>若服务端返回的 Header 中包含 Sec-WebSocket-Extensions, 但该字段值并不在发起握手时传递的 Sec-WebSocket-Extensions 的列表中, 则终止握手</li>
<li>若服务端返回的 Header 中包含 Sec-WebSocket-Protocol, 但该字段值并不在发起握手时传递的 Sec-WebSocket-Protocol 的值列表中, 则终止握手</li>
</ol>
<h3 id="分片逻辑"><a href="#分片逻辑" class="headerlink" title="分片逻辑"></a>分片逻辑</h3><p><strong>不分片</strong>：FIN &#x3D; 1 ； Opcode &#x3D; 文本类型<br><strong>分片</strong>：<br>第一片：	FIN &#x3D; 0 ； Opcode &#x3D; 文本类型<br>中间片：	FIN &#x3D; 0 ； Opcode &#x3D; 0<br>最后一片：	FIN &#x3D; 1 ； Opcode &#x3D; 文本类型  </p>
<h3 id="控制命令"><a href="#控制命令" class="headerlink" title="控制命令"></a>控制命令</h3><ol>
<li>Close frame ：接收到一方发来的 close frame 后，需要返回 close frame；</li>
<li>Ping frame ：心跳机制，websocket 的 Keep-Alive 机制</li>
<li>Pong frame ：接收到 ping 后，需要立即返回pong</li>
</ol>
<h3 id="心跳机制"><a href="#心跳机制" class="headerlink" title="心跳机制"></a>心跳机制</h3><p>客户端发起 Ping 命令，服务端返回 Pong 命令；超时则认为断开连接了</p>
<h3 id="安全"><a href="#安全" class="headerlink" title="安全"></a>安全</h3><p>建立连接时必须在请求头加上 Origin 字段，值为对应的域名；服务端会对 Origin 进行过滤，如果验证不通过返回403</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">[request setValue:@&quot;https://online.xxxx.xxxx&quot; forHTTPHeaderField:@&quot;Origin&quot;];</span><br></pre></td></tr></table></figure>

<h3 id="疑问"><a href="#疑问" class="headerlink" title="疑问"></a>疑问</h3><h4 id="1-TCP-UDP-协议头部都有端口、和校验这些，为什么-websocket-没有"><a href="#1-TCP-UDP-协议头部都有端口、和校验这些，为什么-websocket-没有" class="headerlink" title="1. TCP UDP 协议头部都有端口、和校验这些，为什么 websocket 没有"></a>1. TCP UDP 协议头部都有端口、和校验这些，为什么 websocket 没有</h4><p>因为 websocket 是基于 TCP 的，底层 TCP 传输；websocket 应用层协议，TCP传输层协议</p>
<h4 id="2-为什么客户端发送数据需要掩码，服务端发送数据又不需要掩码"><a href="#2-为什么客户端发送数据需要掩码，服务端发送数据又不需要掩码" class="headerlink" title="2. 为什么客户端发送数据需要掩码，服务端发送数据又不需要掩码"></a>2. 为什么客户端发送数据需要掩码，服务端发送数据又不需要掩码</h4><p>掩码实际上就是简单异或计算出来的值，本身并不具备很强的安全性；之所以需要掩码，为了防止早期版本的协议中存在的代理缓存污染攻击（proxy cache poisoning attacks）等问题。</p>
<h4 id="3-websocket-怎么处理粘包拆包问题的"><a href="#3-websocket-怎么处理粘包拆包问题的" class="headerlink" title="3. websocket 怎么处理粘包拆包问题的"></a>3. websocket 怎么处理粘包拆包问题的</h4><p>通过 FIN 跟 Opcode 来判断</p>
<h3 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h3><p><a target="_blank" rel="noopener" href="https://zhuanlan.zhihu.com/p/407711596">WebSocket 协议完整解析</a><br><a target="_blank" rel="noopener" href="https://www.cnblogs.com/chyingp/p/websocket-deep-in.html">WebSocket协议：5分钟从入门到精通</a><br><a target="_blank" rel="noopener" href="https://chenjianlong.gitbooks.io/rfc-6455-websocket-protocol-in-chinese/content/index.html">RFC-6455 WebSocket 协议翻译</a></p>

    </div>

    
    
    

    <footer class="post-footer">
          <div class="post-tags">
              <a href="/tags/WebSocket/" rel="tag"># WebSocket</a>
          </div>

        

          <div class="post-nav">
            <div class="post-nav-item">
                <a href="/2021/10/NetworkProtocol/SRWebSocket/SRWebSocket/" rel="prev" title="SRWebSocket 源码解析">
                  <i class="fa fa-chevron-left"></i> SRWebSocket 源码解析
                </a>
            </div>
            <div class="post-nav-item">
                <a href="/2022/03/iOS/iOS%E5%AF%B9%E8%B1%A1%E4%BB%80%E4%B9%88%E6%97%B6%E5%80%99%E5%8A%A0%E5%85%A5%E8%87%AA%E5%8A%A8%E9%87%8A%E6%94%BE%E6%B1%A0/" rel="next" title="ARC下，对象什么时候加入自动释放池">
                  ARC下，对象什么时候加入自动释放池 <i class="fa fa-chevron-right"></i>
                </a>
            </div>
          </div>
    </footer>
  </article>
</div>






</div>
  </main>

  <footer class="footer">
    <div class="footer-inner">


<div class="copyright">
  &copy; 2015 – 
  <span itemprop="copyrightYear">2022</span>
  <span class="with-love">
    <i class="fa fa-heart"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">vhuichen</span>
</div>
  <div class="powered-by">Powered by <a href="https://hexo.io/" rel="noopener" target="_blank">Hexo</a> & <a href="https://theme-next.js.org/pisces/" rel="noopener" target="_blank">NexT.Pisces</a>
  </div>

    </div>
  </footer>

  
  <script src="https://cdnjs.cloudflare.com/ajax/libs/animejs/3.2.1/anime.min.js" integrity="sha256-XL2inqUJaslATFnHdJOi9GfQ60on8Wx1C2H8DYiN1xY=" crossorigin="anonymous"></script>
<script src="/js/comments.js"></script><script src="/js/utils.js"></script><script src="/js/motion.js"></script><script src="/js/next-boot.js"></script>

  





  





</body>
</html>
